/**
 * forum
 * zhanjung
 */
package com.junhong.auth.backingbean;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;

import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import javax.inject.Named;

import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.UploadedFile;
import org.slf4j.Logger;

import com.junhong.auth.common.Login;
import com.junhong.auth.entity.User;
import com.junhong.auth.service.UserEjb;
import com.junhong.forum.backingbean.AbstractBacking;
import com.junhong.forum.common.Constants;
import com.junhong.forum.common.Messages;
import com.junhong.forum.common.SendEmailService;
import com.junhong.forum.datamodel.LazyReplyDataModel;
import com.junhong.forum.datamodel.LazyThreadDataModel;
import com.junhong.forum.entity.AbstractEntity;
import com.junhong.forum.entity.ForumReply;
import com.junhong.forum.exceptions.AuthorizationFailException;
import com.junhong.util.EncryptionUtil;
import com.junhong.util.HttpUtil;
import com.junhong.util.PictureUtil;
import com.junhong.util.ViewScoped;
import com.junhong.util.WebConfigUtil;

@ViewScoped
@Named
public class UserBackingBean extends AbstractBacking {
	private static final long	serialVersionUID	= 01l;

	/* ------------instance Variable-------------- */

	@EJB
	private UserEjb				userEjb;
	@Inject
	private Login				login;

	@Inject
	private LazyThreadDataModel	myDataModel;

	@Inject
	private LazyReplyDataModel	myReplyDataModel;

	private User				user				= new User();
	// used in the profile page
	private User				basicUser			= new User();
	private String				profiletab			= Constants.PROFILE_TAB_BASICPROFILE;

	private String				prefix;
	private ForumReply			reply;
	@Inject
	private Logger				logger;

	private boolean				isSystemProfilePic	= false;

	@Inject
	private SendEmailService	sendEmailService;

	private Future<Integer>		sendResetPwdResult;

	/* -------------business logic----------------- */

	/**
	 * for basic user info update
	 */
	public void saveUserBasicInfo() {
		userEjb.updateUser(this.basicUser);
		FacesMessage message = Messages.getMessage("", "save_success", null);
		message.setSeverity(FacesMessage.SEVERITY_INFO);
		FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("SAVE_SUCCESS", message.getSummary());

	}

	public void changePassword() {
		String oldPwd = (String) FacesContext.getCurrentInstance().getViewRoot().getViewMap(false).get("oldPassword");
		boolean isvalid = login.verifyUser(basicUser.getUserId(), oldPwd);
		FacesMessage message;
		if (isvalid) {
			this.basicUser.setPassword(EncryptionUtil.md5(this.basicUser.getPassword()));
			this.basicUser.setPasswordagain(EncryptionUtil.md5(this.basicUser.getPassword()));
			update(this.basicUser);
			message = Messages.getMessage("", "basic_profile_change_password_suc", null);
			message.setSeverity(FacesMessage.SEVERITY_INFO);

		} else {
			message = Messages.getMessage("", "basic_profile_change_password_fail", null);
			message.setSeverity(FacesMessage.SEVERITY_ERROR);
		}

		this.getRequestMap().put("CHANGE_PWD_RESULT", message.getSummary());

	}

	public void loadBasicUser() {

		User user = login.getCurrentUser();
		// refresh the user
		user = userEjb.getUserById(user.getId());
		if (null != user) {
			basicUser = user;
		}

	}

	/**
	 * 
	 * @param user
	 * @return
	 */
	public String enroll() {
		User tempUser = this.user;
		tempUser.setUserGroup(this.findUserGroup(Constants.USERGROUP_REGISTERED));
		tempUser.setProfilePicName(Constants.PROFILE_PIC_DEFAULT_VALUE);

		// encrypt the password
		tempUser.setPassword(EncryptionUtil.md5(tempUser.getPassword()));
		tempUser.setPasswordagain(EncryptionUtil.md5(tempUser.getPasswordagain()));

		tempUser.setLastLogin(new Date());

		userEjb.createUser(tempUser);
		login.initializeUserLogin(tempUser);

		return Constants.NavSuccess;
	}

	public void update(User user) {
		userEjb.updateUser(user);
	}

	public void delete(User user) {
		userEjb.deleteUser(user);

	}

	public User getUser(int id) {
		return userEjb.getUserById(id);
	}

	/**
	 * check if the password entered twice matches with each other
	 * 
	 * @param context
	 * @param component
	 * @param value
	 */
	public void checkPasswordMatch(FacesContext context, UIComponent component, Object value) {

		UIInput passwordInput = (UIInput) component.findComponent("password");
		Object pwdObject = passwordInput.getLocalValue() == null ? passwordInput.getSubmittedValue() : passwordInput.getLocalValue();
		String pwd = pwdObject.toString();
		String pwdagain = value.toString();
		if (!pwd.equals(pwdagain)) {

			FacesMessage message = Messages.getMessage("", "PassWordNOTMatch", null);
			message.setSeverity(FacesMessage.SEVERITY_ERROR);
			throw new ValidatorException(message);
			/*
			 * this is another way to show the validation error message
			 * FacesContext context1 = FacesContext.getCurrentInstance();
			 * context1.addMessage(component.getClientId(), message);
			 * context1.renderResponse();
			 */
		}

	}

	@Override
	protected void processBusiness(String action, AbstractEntity entity) throws AuthorizationFailException {
		// LEAVE EMPTY INDENDEDLY

	}

	public List<String> getUserids(String query) {
		return userEjb.getUserIds(query);
	}

	public void editUser() {
		user = userEjb.getUserByUserId(user.getUserId());

	}

	public void lockUser(boolean lock) {
		user = userEjb.getUserByUserId(user.getUserId());
		user.setLocked(lock);
		userEjb.updateUser(user);
	}

	public void deleteUser() {
		user = userEjb.getUserByUserId(user.getUserId());
		userEjb.deleteUser(user);
		user = new User();
		FacesMessage message = Messages.getMessage("", "user_delete_suc_message", null);
		message.setSeverity(FacesMessage.SEVERITY_INFO);
		FacesContext.getCurrentInstance().addMessage(null, message);
	}

	// pop user for view profile
	public void populateUser(String userId) {
		basicUser = userEjb.getUserByUserId(userId);

	}

	public void validateOldPassword(FacesContext context, UIComponent component, Object value) {
		if (value == null) {
			return;
		}
		String oldpwd = (String) value;

		boolean isValid = login.verifyUser(basicUser.getUserId(), oldpwd);
		if (!isValid) {
			FacesMessage message = Messages.getMessage("", "invalid_password", null);
			message.setSeverity(FacesMessage.SEVERITY_ERROR);

			throw new ValidatorException(message);
		}
	}

	/**
	 * get all init messageboxcontent.xhtml
	 * 
	 * @param profileTab
	 */
	public void initMessages(String profileTab) {
		this.setProfiletab(profileTab);
		// messageBackingBean.fetchAllInboxSentArchieveMessages();
	}

	public void loadMyPosts() {
		myDataModel.setSource(Constants.USER_TAB_MYPOST);
	}

	public void loadMyWatchlist() {
		myDataModel.setSource(Constants.USER_TAB_MYWATCHLIST);
	}

	public void viewReply(ForumReply reply) {
		this.reply = reply;

	}

	/**
	 * listener if Systme profile pic is selected
	 */
	public void updateProfilePic() {

		if (this.isSystemProfilePic) {
			String profilePicName = this.basicUser.getProfilePicName();
			updateCurrUserProfilePic(profilePicName);
		}
		// set success message
		FacesMessage message = Messages.getMessage("", "save_success", null);
		message.setSeverity(FacesMessage.SEVERITY_INFO);
		FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("SAVE_SUCCESS", message.getSummary());

	}

	/**
	 * handler for profile picture upload
	 * 
	 * @param event
	 */
	public void handleProfilePicFileUpload(FileUploadEvent event) {
		FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
		FacesContext.getCurrentInstance().addMessage(null, msg);
		UploadedFile uploadedFile = event.getFile();

		// deprive file name;
		StringBuilder fileName = new StringBuilder(getCurrentUser().getUserId());
		String profilePicFileName = fileName.append(".jpg").toString();

		String destDir = WebConfigUtil.profilePicDir;
		if (destDir == null) {
			String profileRelativePath = File.separator + "resources" + File.separator + "profilepic";
			destDir = HttpUtil.getRealApplicationPath(getFacesContext()) + profileRelativePath;
		}
		logger.info("profile pic destination Dir:" + destDir);

		File file = null;
		OutputStream os = null;
		try {
			File pic_dir = new File(destDir);
			if (!pic_dir.exists()) {
				pic_dir.mkdir();
			}

			BufferedImage resizedImg = ImageIO.read(uploadedFile.getInputstream());
			// shrink the pictures
			resizedImg = PictureUtil.resize(resizedImg);

			file = new File(destDir, profilePicFileName);
			// check if the file exist
			if (file.exists()) {
				file.delete();
			}
			file.createNewFile();
			os = new FileOutputStream(file);
			ImageIO.write(resizedImg, "jpg", os);
		} catch (FileNotFoundException e) {
			logger.error("Not able to save the profile pic. Throw File not found error");
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error("Not able to save the profile pic. throw IOException");
			logger.error(e.getMessage());
		} finally {
			if (os != null) {
				try {
					os.close();
				} catch (IOException e) {
					logger.error(e.getMessage());
				}
			}
		}

		// update profilePicname
		updateCurrUserProfilePic(profilePicFileName);

		// set success message
		FacesMessage message = Messages.getMessage("", "save_success", null);
		message.setSeverity(FacesMessage.SEVERITY_INFO);
		FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("SAVE_SUCCESS", message.getSummary());

	}

	/**
	 * listener for system profile picture change
	 * 
	 * @param profilePicFileName
	 */
	private void updateCurrUserProfilePic(String profilePicFileName) {
		User currUser = this.getCurrentUser();
		currUser = userEjb.getUserByUserId(currUser.getUserId());
		if (currUser.getProfilePicName() == null || !currUser.getProfilePicName().equalsIgnoreCase(profilePicFileName)) {
			currUser.setProfilePicName(profilePicFileName);
			userEjb.updateUser(currUser);
			this.setCurrentUser(currUser);
		}
	}

	// ------------------------------reset password

	public void verifyUserIdExist(FacesContext fc, UIComponent component, Object value) {

		if (null != value) {
			String userId = (String) value;
			if (userEjb.getUserByUserId(userId) == null) {
				FacesMessage message = Messages.getMessage(null, "INVALID_USERID", null, true);
				message.setSeverity(FacesMessage.SEVERITY_ERROR);
				this.getFacesContext().addMessage(component.getClientId(), message);
				throw new ValidatorException(message);

			}
		}

	}

	public void verifyEmailExist(FacesContext fc, UIComponent component, Object value) {

		UIInput userIdComp = (UIInput) component.findComponent("userId");
		Object userIdOb = userIdComp.getLocalValue() == null ? userIdComp.getSubmittedValue() : userIdComp.getLocalValue();
		// or you can use userIdComp.getValue() to get the value

		String userId = (String) userIdOb;
		if (null != userId) {
			User user = userEjb.getUserByUserId(userId);
			if (user == null) {
				FacesMessage message = Messages.getMessage(null, "INVALID_USERID", null, false);
				message.setSeverity(FacesMessage.SEVERITY_ERROR);
				this.getFacesContext().addMessage(component.getClientId(), message);
				throw new ValidatorException(message);

			} else {
				user = userEjb.getUserByUserId(userId);
				if (null != user.getEmail()) {
					String email = (String) value;
					if (!user.getEmail().equalsIgnoreCase(email)) {
						FacesMessage message = Messages.getMessage(null, "INVALID_EMAIL", null, false);
						message.setSeverity(FacesMessage.SEVERITY_ERROR);
						this.getFacesContext().addMessage(component.getClientId(), message);
						throw new ValidatorException(message);

					}
				}
			}
		}

	}

	/**
	 * listener for reset password
	 */
	public void resetPassword() {
		sendEmailService.sendResetPassword(this.user.getUserId(), this.user.getEmail());

		FacesMessage message = Messages.getMessage(null, "USER_RESET_EMAIL_SENT_MESSAGE", null, false);
		FacesContext.getCurrentInstance().addMessage(null, message);

		this.getRequestMap().put("RESETPWDEMAILSUC", "TRUE");
	}

	/* -------------getter/setter----------------- */

	public String getPrefix() {
		return prefix;
	}

	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public User getBasicUser() {
		return basicUser;
	}

	public void setBasicUser(User basicUser) {
		this.basicUser = basicUser;
	}

	public String getProfiletab() {
		return profiletab;
	}

	public void setProfiletab(String profiletab) {
		this.profiletab = profiletab;

		User user = this.getCurrentUser();

		if (profiletab.equalsIgnoreCase(Constants.USER_TAB_MYREPLY)) {
			myReplyDataModel.setSource(profiletab);
			myReplyDataModel.setUser(user);

		} else {
			myDataModel.setSource(profiletab);
			myDataModel.setUser(user);

		}

	}

	public String setProfileNUser(String profiletab) {

		this.profiletab = profiletab;

		User user = userEjb.getUserById(basicUser.getId());

		Map<String, Object> sessionMap = this.getSessionMap();
		sessionMap.put(Constants.VIEWPROFILE_USER_4LAZYDATAMODEL, user);
		sessionMap.put(Constants.VIEWPROFILE_SOUCE_4LAZYDATAMODEL, profiletab);
	

		if (profiletab.equalsIgnoreCase(Constants.USER_TAB_MYREPLY)) {
			// myReplyDataModel.setSource(profiletab);
			// myReplyDataModel.setUser(user);

			return "/user/viewmyreply.xhtml?faces-redirect=true";

		} else {
			// myDataModel.setSource(profiletab);
			// myDataModel.setUser(user);
			return "/user/viewmypost.xhtml?faces-redirect=true";
		}

	}

	public void populateSourceNUser() {
		Map<String, Object> sessionMap = this.getSessionMap();
		String source = (String) sessionMap.get(Constants.VIEWPROFILE_SOUCE_4LAZYDATAMODEL);
		User user = (User) sessionMap.get(Constants.VIEWPROFILE_USER_4LAZYDATAMODEL);

		if (source.equalsIgnoreCase(Constants.USER_TAB_MYREPLY)) {
			myReplyDataModel.setSource(source);
			myReplyDataModel.setUser(user);

		} else {
			myDataModel.setSource(source);
			myDataModel.setUser(user);
		}

	}

	/**
	 * @return the myDataModel
	 */
	public LazyThreadDataModel getMyDataModel() {
		return myDataModel;
	}

	/**
	 * @param myDataModel
	 *            the myDataModel to set
	 */
	public void setMyDataModel(LazyThreadDataModel myDataModel) {
		this.myDataModel = myDataModel;
	}

	/**
	 * @return the reply
	 */
	public ForumReply getReply() {
		return reply;
	}

	/**
	 * @param reply
	 *            the reply to set
	 */
	public void setReply(ForumReply reply) {
		this.reply = reply;
	}

	/**
	 * @return the myReplyDataModel
	 */
	public LazyReplyDataModel getMyReplyDataModel() {
		return myReplyDataModel;
	}

	/**
	 * @param myReplyDataModel
	 *            the myReplyDataModel to set
	 */
	public void setMyReplyDataModel(LazyReplyDataModel myReplyDataModel) {
		this.myReplyDataModel = myReplyDataModel;
	}

	/**
	 * @return the isSystemProfilePic
	 */
	public boolean isSystemProfilePic() {
		return isSystemProfilePic;
	}

	/**
	 * @param isSystemProfilePic
	 *            the isSystemProfilePic to set
	 */
	public void setSystemProfilePic(boolean isSystemProfilePic) {
		this.isSystemProfilePic = isSystemProfilePic;
	}

}
